return False
+ def device_remove(self, dev_uuid):
+ """Remove an existing device referred by dev_uuid.
+ """
+
+ if dev_uuid in self['devices']:
+ dev_config = self['devices'].get(dev_uuid)
+ dev_type = dev_config[0]
+
+ del self['devices'][dev_uuid]
+ # Remove dev references for certain device types (see device_add)
+ if dev_type in ('vif', 'vbd', 'vtpm'):
+ param = '%s_refs' % dev_type
+ if param in self:
+ if dev_uuid in self[param]:
+ self[param].remove(dev_uuid)
def device_sxpr(self, dev_uuid = None, dev_type = None, dev_info = None):
"""Get Device SXPR by either giving the device UUID or (type, config).
return None
log.debug("dev = %s", dev)
- return self.getDeviceController(deviceClass).destroyDevice(dev, force)
+
+ dev_control = self.getDeviceController(deviceClass)
+ dev_uuid = dev_control.readBackend(dev, 'uuid')
+
+ ret = None
+
+ try:
+ ret = dev_control.destroyDevice(dev, force)
+ except EnvironmentError:
+ # We failed to detach the device
+ raise VmError("Failed to detach device %d" % dev)
+
+ # update XendConfig
+ if dev_uuid:
+ self.info.device_remove(dev_uuid)
+
+ return ret
def getDeviceSxprs(self, deviceClass):
if self._stateGet() in (DOM_STATE_RUNNING, DOM_STATE_PAUSED):
dev_num += 1
return sxprs
-
def setMemoryTarget(self, target):
"""Set the memory target of this domain.
@param target: In MiB.
import os
DEVICE_CREATE_TIMEOUT = 100
+DEVICE_DESTROY_TIMEOUT = 10
HOTPLUG_STATUS_NODE = "hotplug-status"
HOTPLUG_ERROR_NODE = "hotplug-error"
HOTPLUG_STATUS_ERROR = "error"
devid = int(devid)
+ frontpath = self.frontendPath(devid)
+ if frontpath:
+ backpath = xstransact.Read(frontpath, "backend")
+
# Modify online status /before/ updating state (latter is watched by
# drivers, so this ordering avoids a race).
self.writeBackend(devid, 'online', "0")
self.writeBackend(devid, 'state', str(xenbusState['Closing']))
if force:
- frontpath = self.frontendPath(devid)
- backpath = xstransact.Read(frontpath, "backend")
if backpath:
xstransact.Remove(backpath)
- xstransact.Remove(frontpath)
+ if frontpath:
+ xstransact.Remove(frontpath)
+ return
+
+ # Wait till both frontpath and backpath are removed from
+ # xenstore, or timed out
+ if frontpath:
+ status = self.waitUntilDestroyed(frontpath)
+ if status == Timeout:
+ # Exception will be caught by destroyDevice in XendDomainInfo.py
+ raise EnvironmentError
+ if backpath:
+ status = self.waitUntilDestroyed(backpath)
+ if status == Timeout:
+ # Exception will be caught by destroyDevice in XendDomainInfo.py
+ raise EnvironmentError
self.vm._removeVm("device/%s/%d" % (self.deviceClass, devid))
return (Missing, None)
+ def waitUntilDestroyed(self, path):
+ ev = Event()
+ result = { 'path': path, 'status': Timeout }
+
+ xswatch(path, destroyCallback, ev, result)
+
+ ev.wait(DEVICE_DESTROY_TIMEOUT)
+ return result['status']
+
+
def backendPath(self, backdom, devid):
"""Construct backend path given the backend domain and device id.
self.deviceClass)
+def destroyCallback(devPath, ev, result):
+ log.debug("destroyCallback %s.", devPath)
+
+ list = xstransact.List(result['path'])
+ if list:
+ return 1
+
+ result['status'] = Missing
+ ev.set()
+ log.debug("destroyCallback %s is destroyed", result['path'])
+ return 0
+
def hotplugStatusCallback(statusPath, ev, result):
log.debug("hotplugStatusCallback %s.", statusPath)